
#include "stdafx.h"
#include "callstack.h"
#include "profilingthread.h"
#include "modulestree.h"



__declspec(thread) int		__mods_stack_frame = 0;
__declspec(thread) HMODULE __mods_stack[MAX_CALLSTACK];

int get_mod_stack_size()
{
	return __mods_stack_frame;
}

HMODULE* get_mod_stack_base()
{
	return __mods_stack;
}

void push_hmod( HMODULE hmod )
{
	__mods_stack[__mods_stack_frame] = hmod;
	__mods_stack_frame++;
}

HMODULE pop_hmod()
{
	HMODULE hm = NULL;
	
	if( __mods_stack_frame>0 );
		hm = __mods_stack[ __mods_stack_frame ];

	__mods_stack_frame--;

	if( __mods_stack_frame<0 )
		__mods_stack_frame = 0;

	return hm;
}

void clear_mod_stack()
{
	memset( __mods_stack,0,MAX_CALLSTACK*4 );
	__mods_stack_frame = 0;
}

void dump_callstack( CONTEXT *context1 )
{

	CONTEXT ctx;
	

	
	CONTEXT *context = NULL;
	if( context1 )
		context = context1;
	else
	{
		GetThreadContext( GetCurrentThread(),&ctx );
		context = &ctx;
	}
	clear_mod_stack();
	STACKFRAME sf;

	memset( &sf, 0, sizeof( STACKFRAME ) );

	sf.AddrPC.Offset = context->Eip;
	sf.AddrPC.Mode = AddrModeFlat;
	sf.AddrStack.Offset = context->Esp;
	sf.AddrStack.Mode = AddrModeFlat;
	sf.AddrFrame.Offset = context->Ebp;
	sf.AddrFrame.Mode = AddrModeFlat;

	DWORD machineType = IMAGE_FILE_MACHINE_I386;

	HANDLE hProcess = GetCurrentProcess();
	HANDLE hThread = GetCurrentThread();

	static HMODULE hModProcess = NULL;
	if( !hModProcess )
		hModProcess = ::GetModuleHandle( NULL );

	int i = 0;

	for(;;)
	{
		if( !StackWalk(machineType, hProcess, hThread, &sf, context, 0, SymFunctionTableAccess, SymGetModuleBase, 0 ) )
		{
			break;
		}

		if( sf.AddrFrame.Offset == 0 )
		{
			break;
		} 

		BYTE symbolBuffer[ sizeof( SYMBOL_INFO ) + 1024 ];
		PSYMBOL_INFO pSymbol = ( PSYMBOL_INFO ) symbolBuffer;

		pSymbol->SizeOfStruct = sizeof( symbolBuffer );
		pSymbol->MaxNameLen = 1024;

		HMODULE hm = NULL;
		//BOOL r = ::GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,(LPCSTR)sf.AddrPC.Offset,&hm );

		DWORD addr = sf.AddrPC.Offset;
		{
			int offset = (int) addr - (int)__hModDLL;

			if( offset >=0 && offset<__dwModSize )
			{
				hm = __hModDLL;
			}

		}


		if( !hm )
		{
			hm = get_module_handle_by_addr( sf.AddrPC.Offset );
		}

		if( !hm )
		{
			::GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,(LPCSTR)sf.AddrPC.Offset,&hm );
		}

		if( hm == __hModDLL )
			continue;

		push_hmod( hm );
		
		if(hm == hModProcess)
			break;

		i++;
	}
}

DWORD excep_filter( LPEXCEPTION_POINTERS lpEP )
{
	/**//// init dbghelp.dll
	
	dump_callstack( lpEP->ContextRecord );
	return EXCEPTION_EXECUTE_HANDLER;
}

void init_callstack()
{	
	char szExePath[MAX_PATH];
	::GetModuleFileNameA(NULL,szExePath,MAX_PATH);
	::PathRemoveFileSpecA(szExePath);
	BOOL r = SymInitialize( GetCurrentProcess(), szExePath, TRUE );
	HINSTANCE hInst = ::GetModuleHandle( NULL );
}


void clean_callstack()
{
	SymCleanup( GetCurrentProcess() );
}
